package com.foruo.learn.javaCore;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 实现
 *
 * 三线程，A线程只打印A，B线程只打印B，C线程只打印C
 * 同时启动三线程，最终依次打印ABC,ABC,ABC各10组
 *
 *
 * 总结：
 * 1、Condition 只能用在Lock锁的区间中，即lock.lock()与lock.unlock()之间
 * 2、Condition 主要使用 await() 与 signal()
 * 3、Condition 方法使用时，最好加上try/catch块
 *
 * Condition
 * @author GaoYuan
 */
public class ConditionDemo {

    /** 全局锁 */
    private static Lock lock = new ReentrantLock();

    /** 可执行A的条件 */
    private static Condition conditionA = lock.newCondition();
    /** 可执行B的条件 */
    private static Condition conditionB = lock.newCondition();
    /** 可执行C的条件 */
    private static Condition conditionC = lock.newCondition();

    /** 先执行A */
    private static String status = "A";

    public static void doA(){
        lock.lock();
        try {
            while(!"A".equals(status)){
                // 如果当前不是执行A，则先等待唤醒 （相当于当前线程放弃了lock锁，这样BC才可以竞争锁）
                try{
                    conditionA.await();
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
            System.out.println("A");
            status = "B";
            // 唤醒B执行
            conditionB.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    public static void doB(){
        lock.lock();
        try {
            while(!"B".equals(status)){
                // 如果当前不是执行A，则先等待唤醒
                try{
                    conditionB.await();
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
            System.out.println("B");
            status = "C";
            // 唤醒B执行
            conditionC.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    public static void doC(){
        lock.lock();
        try {
            while(!"C".equals(status)){
                // 如果当前不是执行A，则先等待唤醒
                try{
                    conditionC.await();
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
            System.out.println("C");
            status = "A";
            // 唤醒B执行
            conditionA.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }


    public static void main(String[] args){
        new Thread(()->{
            for(int i=0;i<10;i++){
                doA();
            }
        }).start();

        new Thread(()->{
            for(int i=0;i<10;i++){
                doB();
            }
        }).start();

        new Thread(()->{
            for(int i=0;i<10;i++){
                doC();
            }
        }).start();
    }





}
